<?php

// Namespace

namespace Loop;


// Dependencies

require_once(PATH_LOOP . 'Class/CJobFactory.php');

require_once(PATH_LOOP . 'Model/CApiQuota.php');
require_once(PATH_LOOP . 'Model/CJobInstance.php');
require_once(PATH_LOOP . 'Model/CQuotaInstance.php');


/**
 * 
 */
 
class CJobFactory_Test extends \UnitTestCase
{
	/**
	 *
	 */

	public function setUp()
	{
		// Create jobs

		$job =  new CJob();

		$job->setId(1);
		$job->setApiName('basic');
		$job->setCategory('test_apis');
		$job->setClassName('CTestObjectF');
		$job->setExtensionId(EXTENSION_LOOP);
		$job->setIsRepeatable(0);

		$job->insert();

		$job->setId(2);
		$job->setApiName('functionWithArguments');
		$job->setCategory('test_apis');
		$job->setClassName('CTestObjectF');
		$job->setExtensionId(EXTENSION_LOOP);
		$job->setIsRepeatable(0);

		$job->insert();


		$job->setId(3);
		$job->setApiName('throwException');
		$job->setCategory('test_apis');
		$job->setClassName('CTestObjectF');
		$job->setExtensionId(EXTENSION_LOOP);
		$job->setIsRepeatable(0);

		$job->insert();


		// Create api quotas

		$apiQuota = new CApiQuota();

		$apiQuota->setId(1);
		$apiQuota->setName('basic');
		$apiQuota->setNbRequests(1);
		$apiQuota->setNbTimes(1);
		$apiQuota->setNbTimesMetrics(METRIC_DAY);
		$apiQuota->setApiName('basic');
		$apiQuota->setClassName('CTestObjectF');
		$apiQuota->setExtensionId(EXTENSION_LOOP);

		$apiQuota->insert();
	}


	/**
	 *
	 */

	public function tearDown()
	{
		$usedObjects = array();

		$usedObjects[] = new CJob();
		$usedObjects[] = new CJobInstance();
		$usedObjects[] = new CQuotaInstance();
		$usedObjects[] = new CApiQuota();

		foreach ($usedObjects as $object) 
		{
			$query = 'TRUNCATE TABLE `%1`.`%2`';

			$queryVariables =  array
			(
				$object->databaseName,
				$object->tableName
			);
			
			$object->databaseDriver->executeQuery($query, $queryVariables);
		}
	}


	/**
	 * Runs the eligible jobs and checks the api quota during the processes
	 */

	public function test_runEligiblesJobs()
	{
		$jobFactory = new CJobFactory();
		$job = new CJob();
		$jobInstance = new CJobInstance();
		$quotaInstance = new CQuotaInstance();
		$apiQuota = new CApiQuota();


		/* ##### 1ST CASE : NO ELIGIBLE JOB ##### */

		// Run the eligibles jobs with no released jobs

		$jobFactory->api_runEligiblesJobs();


		// Get the job instances and the quota instances

		$rawJobInstances = $jobInstance->find();
		$rawQuotaInstances = $quotaInstance->find();

		
		// It should return empty eligible job array

		$this->assertEqual(count($rawJobInstances) , 0);
		$this->assertEqual(count($rawQuotaInstances) , 0);


		/* ##### 2ND CASE : 1 ELIGIBLE JOB SUCCESS ##### */

		// Set the job's time of release

		$job->load(1);
		$job->setTimeOfRelease(time());
		$job->save();

		$apiQuota->load(1);
		

		// Run the eligibles jobs

		$jobFactory->api_runEligiblesJobs();


		// Get the job instances and the quota instances

		$rawJobInstances = $jobInstance->find();
		$rawQuotaInstances = $quotaInstance->find();
		$this->assertEqual(count($rawJobInstances) , 1);
		$this->assertEqual(count($rawQuotaInstances) , 1);

		$currentJobInstance = array_pop($rawJobInstances);
		$currentQuotaInstance = array_pop($rawQuotaInstances);
		$jobInstance->loadFromRawObject($currentJobInstance);
		$quotaInstance->loadFromRawObject($currentQuotaInstance);


		// It should return 1 job instance and 1 quota instance

		$this->assertEqual($jobInstance->getStatus() , 'completed');
		$this->assertEqual($jobInstance->getJobId(), $job->getId());
		$this->assertEqual(json_decode($jobInstance->getTrace()), array('for basic API, it\'s ok !'));
		$this->assertNotNull($jobInstance->getTimeOfStart());
		$this->assertNotNull($jobInstance->getTimeOfClosure());
		$this->assertEqual($quotaInstance->getStatus() , 'not_reached');
		$this->assertEqual($quotaInstance->getQuotaId(), $apiQuota->getId());
		$this->assertEqual
		(
			json_decode
			(
				$quotaInstance->getTrace(),
				true
			), 
			array
			(
				'nbRequests' => 1,
				'nbFoundRequests' => count($rawQuotaInstances),
				'status' => 'not_reached'
			)
		);


		// The job is not repeatable so it should be held

		$job->load(1);

		$this->assertFalse($job->isReleased());


		/* ##### 3RD CASE : RUN ELIGIBLE JOBS, 1st step success, 2nd step QUOTA IS REACHED ##### */

		// Set the job as repeatable and release it after the previous case

		$job->load(1);
		$job->setIsRepeatable(1);
		$job->release();
		$job->setDays(date('d'));
		$job->setHours('*');
		$job->setMinutes('*');
		$job->setMonths('*');
		$job->save();


		// Set the api quota number of requests limit to 2	

		$apiQuota->load(1);
		$apiQuota->setNbRequests(2);
		$apiQuota->save();


		// Run the eligibles jobs

		$jobFactory->api_runEligiblesJobs();


		// Get the job instances and the quota instances

		$rawJobInstances = $jobInstance->find();
		$rawQuotaInstances = $quotaInstance->find();


		// We should have 1 more job instance and 1 more quota instance

		$this->assertEqual(count($rawJobInstances), 2);
		$this->assertEqual(count($rawQuotaInstances), 2);


		$currentJobInstance = array_pop($rawJobInstances);
		$currentQuotaInstance = array_pop($rawQuotaInstances);
		$jobInstance->loadFromRawObject($currentJobInstance);
		$quotaInstance->loadFromRawObject($currentQuotaInstance);


		// First call is success

		$this->assertEqual($quotaInstance->getStatus() , 'not_reached');
		$this->assertEqual($quotaInstance->getQuotaId(), $apiQuota->getId());
		$this->assertEqual
		(
			json_decode
			(
				$quotaInstance->getTrace(),
				true
			), 
			array
			(
				'nbRequests' => 2,
				'nbFoundRequests' => count($rawQuotaInstances),
				'status' => 'not_reached'
			)
		);


		// Run the eligibles jobs again

		$jobFactory->api_runEligiblesJobs();


		// Get the job instances and the quota instances

		$rawJobInstances = $jobInstance->find();
		$rawQuotaInstances = $quotaInstance->find();


		// We should have no more job instance and 1 more quota instance

		$this->assertEqual(count($rawJobInstances), 2);
		$this->assertEqual(count($rawQuotaInstances), 3);


		$currentJobInstance = array_pop($rawJobInstances);
		$currentQuotaInstance = array_pop($rawQuotaInstances);
		$jobInstance->loadFromRawObject($currentJobInstance);
		$quotaInstance->loadFromRawObject($currentQuotaInstance);


		// Second call failed, QUOTA IS REACHED !!!

		$this->assertEqual($quotaInstance->getStatus() , 'exceeded');
		$this->assertEqual($quotaInstance->getQuotaId(), $apiQuota->getId());
		$this->assertEqual
		(
			json_decode
			(
				$quotaInstance->getTrace(),
				true
			), 
			array
			(
				'nbRequests' => 2,
				'nbFoundRequests' => count($rawQuotaInstances),
				'status' => 'exceeded'
			)
		);
	}


	/**
	 * Runs the eligible jobs and execute APIs with arguments
	 */

	public function testJobWithArguments()
	{
		$ids = array('1' , '2');
		$reference = '12345678';

		$arguments = array
		(
			'ids' => $ids,
			'reference' => $reference
		);


		$job = new CJob();
		$jobFactory = new CJobFactory();
		$jobInstance = new CJobInstance();

		$job->load(2);
		$job->setArguments(json_encode($arguments));
		$job->setIsRepeatable(1);
		$job->setDays(date('d'));
		$job->setHours('*');
		$job->setMinutes('*');
		$job->setMonths('*');
		$job->setTimeOfRelease(time());

		$job->save();		

		
		// Run the eligible jobs

		$jobFactory->api_runEligiblesJobs();


		// Get the instances

		$rawJobInstances = $jobInstance->find();

		
		// We should have 1 job instance

		$this->assertEqual(count($rawJobInstances) , 1);			
		

		// Extract the instance

		$rawJobInstance = array_pop($rawJobInstances);


		// Load the instance

		$jobInstance->loadFromRawObject($rawJobInstance);	


		// Job API execution succeed

		$this->assertEqual($jobInstance->getStatus() , 'completed');
		$this->assertEqual($jobInstance->getJobId(), $job->getId());
		$this->assertEqual($jobInstance->getTrace(), 'true');			

	}


	/**
	 * Runs the eligible jobs and execute APIs which return exceptions
	 */

	public function test_runEligiblesJobsThrowException()
	{
		$job = new CJob();
		$jobFactory = new CJobFactory();
		$jobInstance = new CJobInstance();

		$job->load(3);
		$job->setIsRepeatable(1);
		$job->setDays(date('d'));
		$job->setHours('*');
		$job->setMinutes('*');
		$job->setMonths('*');
		$job->setTimeOfRelease(time());

		$job->save();		

		
		// Run the eligible jobs

		$jobFactory->api_runEligiblesJobs();


		// Get the job instances

		$rawJobInstances = $jobInstance->find();

		
		// We should have just 1 job instance

		$this->assertEqual(count($rawJobInstances) , 1);			
		

		// Extract the instance

		$rawJobInstance = array_pop($rawJobInstances);


		// Load the instance

		$jobInstance->loadFromRawObject($rawJobInstance);	


		// Job API execution failed

		$this->assertEqual($jobInstance->getStatus() , 'failed');
		$this->assertEqual($jobInstance->getJobId(), $job->getId());
		$this->assertNotNull($jobInstance->getTrace());	
	}
}


?>